package com.zyc.studentstudy.utils

import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream

/**
 * Description :
 * Author :mhwang
 * Date : 2018/4/19
 * Version : V1.0
 */
object ZipUtil {
    private const val TAG = "ZipUtil"

    /**
     * 解压zip到指定的路径
     *  java.lang.IllegalArgumentException: MALFORMED 表示压缩文件内部有中文的名称
     * @param zipFileString ZIP的名称
     * @param outPathString 要解压缩路径
     * @throws Exception
     */
    @JvmStatic
    @Throws(Exception::class)
    fun UnZipFolder(zipFileString: String, outPathString: String) {
        val inZip = ZipInputStream(FileInputStream(zipFileString))
        var zipEntry: ZipEntry?
        var szName: String
        while (inZip.nextEntry.also { zipEntry = it } != null) {
            szName = zipEntry!!.name
            if (zipEntry!!.isDirectory) {
                //获取部件的文件夹名
                szName = szName.substring(0, szName.length - 1)
                val folder = File("$outPathString${File.separator}$szName")
                folder.mkdirs()
            } else {
                val file = File("$outPathString${File.separator}$szName")
                if (!file.exists()) {
                    file.parentFile.mkdirs()
                    file.createNewFile()
                }
                // 获取文件的输出流
                val out = FileOutputStream(file)
                val buffer = ByteArray(1024)
                var len: Int
                // 读取（字节）字节到缓冲区
                while (inZip.read(buffer).also { len = it } != -1) {
                    // 从缓冲区（0）位置写入（字节）字节
                    out.write(buffer, 0, len)
                    out.flush()
                }
                out.close()
            }
        }
        inZip.close()
    }

    /**
     * 压缩成ZIP 方法2
     * @param fileDirPath   压缩文件夹路径
     * @param zipFilePath   压缩文路径
     * @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;false:所有文件跑到压缩包根目录下(注意：
     *                      不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    @JvmStatic
    @Throws(Exception::class)
    fun toZip(fileDirPath: String, zipFilePath: String, keepDirStructure: Boolean) {
        var zos: ZipOutputStream? = null
        try {
            val out = FileOutputStream(File(zipFilePath))
            zos = ZipOutputStream(out)
            val dirFile = File(fileDirPath)
            compress(dirFile, zos, dirFile.name, keepDirStructure)
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            zos?.close()
        }
    }

    /**
     * 递归压缩方法
     * @param sourceFile        源文件
     * @param zos               zip输出流
     * @param name              压缩后的文件夹/文件名称
     * @param keepDirStructure  是否保留原来的目录结构,true:保留目录结构;
     *            false:所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    @JvmStatic
    @Throws(Exception::class)
    private fun compress(sourceFile: File, zos: ZipOutputStream, name: String, keepDirStructure: Boolean) {
        val buf = ByteArray(1024)
        if (sourceFile.isFile) {
            //向zip输出流中添加一个zip实体，构造器中name为zip实体的文件的名字
            zos.putNextEntry(ZipEntry(name))
            //copy文件到zip输出流中
            val input = FileInputStream(sourceFile)
            var len: Int
            while (input.read(buf).also { len = it } != -1) {
                zos.write(buf, 0, len)
            }
            zos.closeEntry()
            input.close()
        } else {
            val listFiles = sourceFile.listFiles()
            if (listFiles.isNullOrEmpty()) {
                //需要保留原来的文件结构时,需要对空文件夹进行处理
                if (keepDirStructure) {
                    //空文件夹的处理
                    zos.putNextEntry(ZipEntry("$name/"))
                    //没有文件，不需要文件的copy
                    zos.closeEntry()
                }
            } else {
                for (file in listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (keepDirStructure) {
                        // 注意：file.getName()前面需要带上父文件夹的名字加一斜杠,不然最后压缩包中就不能保留原来的文件结构,即：所有文件都跑到压缩包根目录下了
                        compress(file, zos, "$name/${file.name}", keepDirStructure)
                    } else {
                        compress(file, zos, file.name, keepDirStructure)
                    }
                }
            }
        }
    }
}